/****************************************************************************
* COSC1283/1284 - Programming Techniques
* Semester 1 2011 Assignment #2 - Gloria Jean's Coffee system
* Full Name        : LE YAN
* Student Number   : 3262302
* Yallara Username : s3262302
* Course Code      : BP232
* Program Code     : COSC1284
* Start up code provided by Christopher Hoobin and Xiaodong Li
****************************************************************************/

#include "gjc.h"
#include "gjc_options.h"
#include "gjc_utility.h"

/****************************************************************************
* Menu option #1: Display Summary
* Allows the user to display a summary of all hot or cold drink categories
* and items.
****************************************************************************/
void displaySummary(GJCType *menu, char categoryType)
{
  if( categoryType == 'H')
  {
    printf("Hot Drinks Summary\n");
    printf("-------------------\n\n");
  }
  else
  {
    printf("Cold Drinks Summary\n");
    printf("-------------------\n\n"); 
  }
  printmenu(menu, categoryType);
}

/* print st to file which fp point to and break the lines at the num column */
static void
fprint(FILE *fp, char *st, int num)
{
  int len, current_len, i, j, flag;
  char buffer[MAX_DESC_LEN];

  if ( fp == NULL || st == NULL )
  {
    fprintf(stderr, "Fatal error!\n");
    exit(FAILURE);
  }

  len = strlen(st);
  
  for(i=0, current_len=0; i < len ;)
  {
    flag = isalnum(st[i])==NON_WORD?NON_WORD:WORD; 
    j = i+1;
    buffer[0] = '\0';

    while( j< len && ( isalnum(st[j])==NON_WORD?NON_WORD:WORD ) == flag )
    {
       j++;
    }
    
    if( j-i+current_len >= num )
    {
      fprintf(fp, "\n%s", strncat(buffer, st+i, j-i) );
      current_len = 0;
    }
    else
    {
      current_len = current_len + j - i;
      fprintf(fp, "%s", strncat(buffer, st+i, j-i) );
    }
   
    i = j;
  }
}

/* write report */
static void
write_report(CategoryTypePtr c )
{
   FILE *fp;
   char st[REPORT_NAME];
   ItemTypePtr current; 
   int i;

   if( c == NULL )
   {
     fprintf(stderr,"Memory Error!\n");
     exit(FAILURE);
   }
   
   sprintf(st, "%s.report", c->categoryID);
   fp = fopen(st, "w");
    
   if( fp == NULL )
   {
     fprintf(stderr, "Cannot open file!\n");
     exit(FAILURE);
   }

   /* generate report */
   fprintf(fp, "Category %s - %s - Detailed Report\n",
           c->categoryID, c->categoryName );
   fprintf(fp, "----------------------------------------");
   fprintf(fp, "--------------------------------------\n\n");
   
   current = c->headItem;
   while( current != NULL )
   {
     fprintf(fp, "Item ID     : %s\n", current->itemID);
     fprintf(fp, "Item Name   : %s\n", current->itemName);
     fprintf(fp, "Prices      : "); 
     /* print price */
     for(i=0; i<NUM_PRICES; i++)
     {
        fprintf(fp, "$");
        fprintf(fp, "%d.", current->prices[i].dollars);
        if( current->prices[i].cents < 10 )
          fprintf(fp, "%d0 ", current->prices[i].cents);
        else
          fprintf(fp, "%d ", current->prices[i].cents);
     }
     fprintf(fp, "\n");
    
     /* print description */
     if( ( strlen(current->itemDescription) ) < BREAK_LINE)
        fprintf(fp, current->itemDescription);
     else
     {
        fprint(fp, current->itemDescription, BREAK_LINE);
     }

     fprintf(fp, "\n\n");
     current = current->nextItem;
   }

   fclose(fp);

}

/****************************************************************************
* Menu option #2: Category Report
* Allows the user to make a new report file for a chosen category.
****************************************************************************/
void categoryReport(GJCType *menu)
{
  char c, id[ID_LEN +1];
  int i; 
  CategoryTypePtr current;

  if( menu == NULL || menu->headCategory == NULL )
  {
    fprintf(stderr, "Memory Error!\n");
    exit(FAILURE);
  }

  while(1)
  {
    i = 0;
    /* print info  */
    printf("Detailed Menu Report\n");
    printf("--------------------\n\n");
    printf("Enter Category id (5 characters): ");

    /* read input */
    c = fgetc(stdin);  
    /* if user input 'enter' */
    if( c == '\n' )
      return; 
    id[i] = c;
    for(i=1; i<ID_LEN; i++)
    {
      if( (c = fgetc(stdin)) == '\n' )
       break; 
      id[i] = c;  
    }
    /* check if user input is too short */
    if( i < ID_LEN )
    {
      fprintf(stderr, "Invalid ID!\n");
      continue;
    }
    
    id[i] = '\0';
    
    if( (c = fgetc(stdin)) != '\n' )
    {
       fprintf(stderr, "Your input is too long!\n");
       readRestOfLine();
       continue;
    }
    
    current = menu->headCategory;
    while( current != NULL )
    {
    
       if( strcmp( current->categoryID , id ) == 0 )
       {
           write_report(current);    
           printf("File %s.report has been created.\n\n", id);
           return;
       }
       current = current->nextCategory;
    }
   
    /* ID not found*/
    fprintf(stderr, "ID not found!\n");
  } 

}


/* generate categoryID */
static char*
getCategoryID(GJCType *menu)
{
  CategoryTypePtr current;
  int max, tmp;
  char *id;

  current = menu->headCategory;
  max = 0; 
 
  /* look for the biggest ID number */
  while( current != NULL )
  {
    tmp = atoi( current->categoryID+1 ); 

    if( max < tmp )
      max = tmp;

    current = current->nextCategory;
  }

  id = (char*)malloc( sizeof(char) * (ID_LEN+1) );
  if( id == NULL )
  {
    fprintf(stderr, "Memory Error!\n");
    exit(FAILURE);
  }
 
  sprintf( id, "C%04d", max+1);
  return id;
  
}


/****************************************************************************
* Menu option #3: Add Category
* Allows the user to add a new category record to the linked list.
****************************************************************************/
void addCategory(GJCType *menu)
{
  CategoryTypePtr new;
  char tmp[TMP_LEN], c;
  char *id;

  int i;
  if( menu == NULL || menu->headCategory == NULL )
  {
     fprintf(stderr, "Memory error!\n");
     exit(FAILURE);
  }

  printf("Add Menu Category\n");
  printf("-----------------\n\n");
  new = (CategoryTypePtr)malloc( sizeof(CategoryType) );  
  new->nextCategory = NULL;
  new->headItem = NULL;
  new->numItems = 0;

  id = getCategoryID(menu);
  strcpy( new->categoryID , id);
  free(id);
  printf("New category ID is %s.\n", new->categoryID);

  while(1)
  {
    printf("Category Name (1-25 characters): ");
    c = getc(stdin);
    i = 0;
    if ( c == '\n' )
    {
       free(new);
       return;
    }
   
    tmp[i] = c;
    for(i=1; i<MAX_NAME_LEN; i++)
    {
      if( (c=getc(stdin)) == '\n' )
        break;
      tmp[i] = c;
    } 
   
    
    if( i>=MAX_NAME_LEN  )
    {
      c = getc(stdin);
      if( c != '\n' )
      {
        fprintf(stderr, "Your input is too long!\n");
        readRestOfLine();
        continue;
      }
      
    }
    tmp[i] = '\0';
    break;
  }
  strcpy(new->categoryName, tmp);
  
  while(1)
  {
    printf("(H)ot or (C)old drink?: ");
    c = getc(stdin);
    if( c == 'H' || c == 'h' || c == 'C' || c == 'c' )
    {
      new->categoryType = toupper(c);
      readRestOfLine();
      break;
    }

    if( c == '\n')
    {
      free(new);
      return;
    }
    fprintf(stderr, "Please input 'H' or 'C'\n");
    readRestOfLine();
  }

  while(1)
  {
    printf("Description (1-250 characters): ");
     
    c = getc(stdin);
    i = 0;
    if ( c == '\n')
    {
       free(new);
       return;
    }
    tmp[i] = c;
    for(i=1; i<MAX_DESC_LEN; i++)
    {
      if( (c=getc(stdin)) == '\n' )
        break;
      tmp[i] = c;
    }
    
    if( i >= MAX_DESC_LEN )
    {
       c = getc(stdin);
       if( c != '\n' )
       {
          fprintf(stderr, "Your input is too long!\n");
          readRestOfLine();
          continue;
       }

    }
    tmp[i] = '\0';
    break;
  }
  strcpy(new->categoryDescription, tmp);
  if( insertlist(menu, new) == FAILURE )
  {
     fprintf(stderr,"Fatal Error!\n");
     exit(FAILURE);
  }

  printf("Add Category sucessfully!\n");
}


/****************************************************************************
* Menu option #4: Delete Category
* Deletes a category and all corresponding items.
****************************************************************************/
void deleteCategory(GJCType *menu)
{
  char c, tmp[ID_LEN];
  int i;

  printf("Delete Menu Category\n");
  printf("--------------------\n");
  printf("\n");
  printf("Warning: All menu item data for a menu category will be deleted if\
you proceed.\n\n");
 
  while(1)
  {
    i = 0;
    printf("Menu category ID: ");
    if( (c=fgetc(stdin)) == '\n' )
      return;
    tmp[i] = c;

    for(i=1; i<ID_LEN; i++)
    {
       if( (c=fgetc(stdin)) == '\n' )
        break; 

       tmp[i] = c;
    }
    
    if( i < ID_LEN )
    {
      fprintf(stderr, "Invalid ID!\n");
      continue;
    }
    
    c=fgetc(stdin);
    if( c != '\n' )
    {
      fprintf(stderr, "Your input is too long!\n");
      readRestOfLine();
      continue;
    }
    
    tmp[i] = '\0';
    
    if ( delete_category(menu, tmp) == FAILURE )
    {
       fprintf(stderr, "ID not found!\n");
       continue;
    }
    break;
  }
}


/* get category */
static CategoryTypePtr 
getCategory(GJCType *menu, char* id) 
{
  CategoryTypePtr current;

  if( menu == NULL || id == NULL )
  {
    fprintf(stderr, "Fatal error!\n");
    exit(FAILURE);
  }
 
  current = menu->headCategory;
  
  while( current != NULL )
  {
    if ( strcmp( current->categoryID , id ) == 0 )
    {
       return current;  
    }
    current = current->nextCategory;
  }

  return NULL;

}

/* generate item id */
static char*
getItemID(GJCType *menu)
{
  CategoryTypePtr currentC;
  ItemTypePtr currentI;
  int max, tmp;
  char *id;

  currentC = menu->headCategory; 
  max = 0; 
 
  /* look for the biggest ID number */
  while( currentC != NULL )
  {
    currentI = currentC->headItem;
    while( currentI != NULL )
    {
       tmp = atoi( currentI->itemID+1 ); 

       if( max < tmp )
         max = tmp;

       currentI = currentI->nextItem;
    }
    currentC = currentC->nextCategory;
  }

  id = (char*)malloc( sizeof(char) * (ID_LEN+1) );
  if( id == NULL )
  {
    fprintf(stderr, "Memory Error!\n");
    exit(FAILURE);
  }
 
  sprintf( id, "I%04d", max+1);
   
  return id;
  
}

/****************************************************************************
* Menu option #5: Add Item
* Allows the user to add a new item to an existing category. An error
* message is given if the category doesn't exist.
****************************************************************************/
void addItem(GJCType *menu)
{
  char c, tmp[TMP_LEN]; 
  char *size[] = { "Small Price ($0.05-$9.95): ",
                   "Medium Price ($0.05-$9.95): ",
                   "Large Price ($0.05-$9.95): " };
  ItemTypePtr new;
  int i, j;
  CategoryTypePtr category;
  double p;
  char *id;

  new = (ItemTypePtr)malloc( sizeof(ItemType) );
  if ( new == NULL )
  {
    fprintf(stderr, "Memory error!\n");
    exit(FAILURE);
  }
  printf("Add Menu Item\n");
  printf("-------------\n");
  printf("\n");
  
  while(1)
  {
     i = 0;
     printf("Category ID (5 characters): ");
     c = getc(stdin);
     if( c == '\n' )
     {
       free(new);
       return;
     }
     tmp[i++] = c;
     
     while( i<ID_LEN )
     {
        if ( (c = getc(stdin)) == '\n' )
        {
          break; 
        }
        tmp[i++] = c;  
     }
    
     if( i<ID_LEN )
     {
       fprintf(stderr, "Invalid ID!\n"); 
       continue;
     }

     if( (c = getc(stdin)) != '\n' )
     {
       fprintf(stderr, "Your input is too much!\n");
       readRestOfLine();
       continue;  
     }
     tmp[i] = '\0'; 
     
     if ( (category=getCategory(menu, tmp)) == NULL )
     {
       fprintf(stderr,"ID not found!\n");
       continue;
     }
   
     break;
  }
  
  id = getItemID(menu);
  strcpy( new->itemID, id );
  free(id);
  printf("New item ID is %s.\n", new->itemID);

  /* get name */
  while(1)
  {
    printf("Item name (1-25 characters): ");
    c = fgetc(stdin);
    i = 0;
    if( c == '\n' )
    { 
      free(new);
      return;
    }
    tmp[i++] = c;
    while( i<MAX_NAME_LEN+1 && (c=fgetc(stdin)) != '\n' )
    {
      tmp[i++] = c;  
    }

    if( i >= MAX_NAME_LEN+1 )
    {
      fprintf(stderr, "Your input is too long!\n");
      readRestOfLine();
      continue;
    }
    tmp[i] = '\0'; 
    strcpy( new->itemName, tmp);
    break;
  } 

  /* get prices */
  for(i=0; i<NUM_PRICES; i++)
  {
    while(1)
    {
      printf("%s", size[i]);
      j = 0; 
      c = fgetc(stdin);
      if( c == '\n' )
      {
        free(new);
        return;
      }
      tmp[j++] = c;

      while( (c=fgetc(stdin)) != '\n' )
      {
        tmp[j++] = c; 
      }
      tmp[j] = '\0';
      p = atof(tmp);
      if( p <= 0 || p > MAX_PRICE )
      {
        fprintf(stderr, "You input is invalid!\n");
        continue;
      }
      new->prices[i].dollars = (int)p;
      new->prices[i].cents = ((int)(p*1000.0/10))%100;
      break;
    } 
  }

  /* get description */
  while(1)
  {
    printf("Description (1-250 characters): ");
    c = fgetc(stdin);
    i = 0;
    if( c == '\n' )
    { 
      free(new);
      return;
    }
    tmp[i++] = c;
    while( i<MAX_DESC_LEN+1 && (c=fgetc(stdin)) != '\n' )
    {
      tmp[i++] = c;  
    }

    if( i >= MAX_DESC_LEN+1 )
    {
      fprintf(stderr, "Your input is too long!\n");
      readRestOfLine();
      continue;
    }
    
    tmp[i] = '\0';
    strcpy( new->itemDescription, tmp);
    break;
  } 
  new->nextItem = NULL;
  insertitem( menu, category->categoryID, new);
  printf("Insert Item successfully!\n\n"); 
}


/****************************************************************************
* Menu option #6: Delete Item
* Deletes a single item from a particular category.
****************************************************************************/
void deleteItem(GJCType *menu)
{
  char item[ID_LEN], category[ID_LEN], c;
  int i;
  CategoryTypePtr ctgry;
  ItemTypePtr last, current;

  printf("Delete Menu Item\n");
  printf("----------------\n\n");
  
  while(1)
  {
     i = 0;
     printf("Category ID (5 characters): ");
     c = getc(stdin);
     if( c == '\n' )
     {
       return;
     }
     category[i++] = c;
     
     while( i<ID_LEN )
     {
        if ( (c = getc(stdin)) == '\n' )
        {
          break; 
        }
        category[i++] = c;  
     }
    
     if( i<ID_LEN )
     {
       fprintf(stderr, "Invalid ID!\n"); 
       continue;
     }

     if( (c = getc(stdin)) != '\n' )
     {
       fprintf(stderr, "Your input is too much!\n");
       readRestOfLine();
       continue;  
     }
     category[i] = '\0'; 
     
     if ( (ctgry=getCategory(menu, category)) == NULL )
     {
       fprintf(stderr,"ID not found!\n");
       continue;
     }
  
     if( ctgry->headItem == NULL )
     {
       fprintf(stderr,"The category is empty!\n");
       continue;
     }

     while(1)
     {
        i = 0;
        printf("Item ID (5 characters): ");
        c = getc(stdin);
        if( c == '\n' )
        {
          return;
        }
        item[i++] = c;
     
        while( i<ID_LEN )
        {
          if ( (c = getc(stdin)) == '\n' )
          {
            break; 
          }
          item[i++] = c;  
        }
    
        if( i<ID_LEN )
        {
          fprintf(stderr, "Invalid ID!\n"); 
          continue;
        }

        if( (c = getc(stdin)) != '\n' )
        {
          fprintf(stderr, "Your input is too much!\n");
          readRestOfLine();
          continue;  
        }
        item[i] = '\0'; 
     
   
        last = NULL;
        current = ctgry->headItem;
        
        if( strcmp( current->itemID, item ) == 0 )
        {
          ctgry->headItem = current->nextItem;
          free(current);
          printf("Delete item successfully!\n");
          return;
        }

        while( current != NULL )
        {
          if( strcmp( current->itemID, item ) == 0 )
          {
            last->nextItem = current->nextItem;
            free(current);
            printf("Delete item successfully!\n");
            return;
          }
          last = current;
          current = current->nextItem;
        }

        fprintf(stderr, "id is not found!");
        fprintf(stderr, "If the id you want to delete is not in the the \
category.\n");
        fprintf(stderr, "Please press 'Enter' to return to main menu and \
select option 7 again\n");
     }
  }
 


}


static void
savemenu(GJCType *menu, char *menuFile)
{
   FILE *fp;
   CategoryTypePtr current;

   fp = fopen( menuFile, "w" );
   if( fp == NULL )
   {
     fprintf(stderr, "Fatal Error!\n");
     exit(FAILURE);
   }
   current = menu->headCategory; 
   
   while( current != NULL )
   {
     fprintf(fp, "%s|%c|%s|%s\n", current->categoryID,
             current->categoryType, current->categoryName,
             current->categoryDescription);
     current = current->nextCategory;
   }
   fclose(fp); 
}

static void 
savesubmenu(GJCType *menu, char *submenuFile)
{
  FILE *fp;
  char tmp[TMP_LEN];
  ItemTypePtr currentI;
  CategoryTypePtr currentC;
  int i;

  fp = fopen( submenuFile , "w" );
  if( fp == NULL )
  {
    fprintf(stderr, "Fatal Error!\n");
    exit(FAILURE);
  }
  currentC = menu->headCategory;
  
  while( currentC != NULL )
  {
    currentI = currentC->headItem; 
    while( currentI != NULL )
    {
      fprintf(fp, "%s|%s|%s|", currentI->itemID,
              currentC->categoryID, currentI->itemName);
      for( i=0; i<NUM_PRICES; i++ )
      {
        sprintf(tmp, "%d.%02d", currentI->prices[i].dollars,
                currentI->prices[i].cents);
        fprintf(fp, "%s|", tmp);
      }
             
      fprintf(fp, "%s\n", currentI->itemDescription);
      currentI = currentI->nextItem;
    }
    currentC = currentC->nextCategory;
  }

  fclose(fp);
}

/****************************************************************************
* Menu option #7: Save and Exit
* Saves all system data back to the original files. This function does not
* terminate the program - this is left to the main() function instead.
****************************************************************************/
void saveData(GJCType *menu, char *menuFile, char *submenuFile)
{
  
  if( menu == NULL || menuFile == NULL || submenuFile == NULL )
  {
    fprintf(stderr, "Fatal Error!\n");
    exit(FAILURE);
  }
  
  savemenu(menu, menuFile);
  savesubmenu(menu, submenuFile);  
}
